//Copyright 2011 - Jonathan Allen

using System;
using System.Globalization;
using System.Windows.Data;
using System.Collections;
using System.Diagnostics.Contracts;
#if NUMERICS
using System.Numerics;
#endif

namespace Granite.Xaml.Converters
{
	/// <summary>
	/// Converts null to false.
	/// Converts 0 to true, other numbers to false.
    /// Throws if the type isn't a number, string, or list
    /// </summary>
	[ValueConversion(typeof(Byte), typeof(bool))]
	[ValueConversion(typeof(SByte), typeof(bool))]
	[ValueConversion(typeof(Int16), typeof(bool))]
	[ValueConversion(typeof(UInt16), typeof(bool))]
	[ValueConversion(typeof(Int32), typeof(bool))]
	[ValueConversion(typeof(UInt32), typeof(bool))]
	[ValueConversion(typeof(Int64), typeof(bool))]
	[ValueConversion(typeof(UInt64), typeof(bool))]
	[ValueConversion(typeof(Decimal), typeof(bool))]
	[ValueConversion(typeof(Single), typeof(bool))]
	[ValueConversion(typeof(Double), typeof(bool))]
	[ValueConversion(typeof(Byte?), typeof(bool))]
	[ValueConversion(typeof(SByte?), typeof(bool))]
	[ValueConversion(typeof(Int16?), typeof(bool))]
	[ValueConversion(typeof(UInt16?), typeof(bool))]
	[ValueConversion(typeof(Int32?), typeof(bool))]
	[ValueConversion(typeof(UInt32?), typeof(bool))]
	[ValueConversion(typeof(Int64?), typeof(bool))]
	[ValueConversion(typeof(UInt64?), typeof(bool))]
	[ValueConversion(typeof(Decimal?), typeof(bool))]
	[ValueConversion(typeof(Single?), typeof(bool))]
	[ValueConversion(typeof(Double?), typeof(bool))]
	[ValueConversion(typeof(Byte), typeof(bool?))]
	[ValueConversion(typeof(SByte), typeof(bool?))]
	[ValueConversion(typeof(Int16), typeof(bool?))]
	[ValueConversion(typeof(UInt16), typeof(bool?))]
	[ValueConversion(typeof(Int32), typeof(bool?))]
	[ValueConversion(typeof(UInt32), typeof(bool?))]
	[ValueConversion(typeof(Int64), typeof(bool?))]
	[ValueConversion(typeof(UInt64), typeof(bool?))]
	[ValueConversion(typeof(Decimal), typeof(bool?))]
	[ValueConversion(typeof(Single), typeof(bool?))]
	[ValueConversion(typeof(Double), typeof(bool?))]
	[ValueConversion(typeof(Byte?), typeof(bool?))]
	[ValueConversion(typeof(SByte?), typeof(bool?))]
	[ValueConversion(typeof(Int16?), typeof(bool?))]
	[ValueConversion(typeof(UInt16?), typeof(bool?))]
	[ValueConversion(typeof(Int32?), typeof(bool?))]
	[ValueConversion(typeof(UInt32?), typeof(bool?))]
	[ValueConversion(typeof(Int64?), typeof(bool?))]
	[ValueConversion(typeof(UInt64?), typeof(bool?))]
	[ValueConversion(typeof(Decimal?), typeof(bool?))]
	[ValueConversion(typeof(Single?), typeof(bool?))]
	[ValueConversion(typeof(Double?), typeof(bool?))]
	public partial class ZeroToTrueConverter : OneWayMarkupValueConverter<ZeroToTrueConverter>
	{
		/// <summary>
		/// 
		/// </summary>
		/// <param name="value">Any numeric type</param>
		/// <param name="targetType">Boolean</param>
		/// <param name="parameter"></param>
		/// <param name="culture"></param>
		/// <returns></returns>
        [Pure]
        public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
		{
			CheckTargetType(targetType, typeof(bool), typeof(bool?));

			if (value == null)
				return false;

			//Common types
			if (value is Int32)
				return (Int32)value == 0;
			if (value is Decimal)
				return (Decimal)value == 0;
			if (value is Single)
				return (Single)value == 0;
			if (value is Double)
				return (Double)value == 0;

            if (value is string)
                return ((string)value).Length == 0;
            if (value is ICollection)
                return ((ICollection)value).Count == 0;
            if (value is IEnumerable)
            {
                var enumerator = ((IEnumerable)value).GetEnumerator();

                if (enumerator.MoveNext()) //count >= 1
                    return false;
                else
                    return true;
            }

			//other numeric types
			if (value is Byte)
				return (Byte)value == 0;
			if (value is SByte)
				return (SByte)value == 0;
			if (value is Int16)
				return (Int16)value == 0;
			if (value is UInt16)
				return (UInt16)value == 0;
			if (value is UInt32)
				return (UInt32)value == 0;
			if (value is Int64)
				return (Int64)value == 0;
			if (value is UInt64)
				return (UInt64)value == 0;
			
#if NUMERICS
			if (value is BigInteger)
				return (BigInteger)value == 0;
#endif

			throw new ArgumentException("value is not a number", "value");
		}

	}

#if NUMERICS
	[ValueConversion(typeof(BigInteger), typeof(bool))]
	[ValueConversion(typeof(BigInteger?), typeof(bool))]
	[ValueConversion(typeof(BigInteger), typeof(bool?))]
	[ValueConversion(typeof(BigInteger?), typeof(bool?))]
	public partial class ZeroToTrueConverter
	{

	}

#endif
}
